﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace ShelSystemViewer
{
    public partial class PlayerUpdateForm : Form
    {
        private static string AddPlayerURL = "";
        private static Regex LettersOnlyRegex = new Regex(@"^[a-zA-Z]*$");
        private static Regex DigitsOnlyRegex = new Regex(@"^[0-9]*$");
        private static Regex PhoneNumberRegex = new Regex(@"^[0-9]{3}-[0-9]{3}-[0-9]{4}$");
        private static Regex BirthdayRegex = new Regex(@"^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$");
        private static Regex DecimalNumberRegex = new Regex(@"^[0-9\.]*$");
        private bool IsNewPlayer;
        private Player OrigPlayerInfo;
        private Contact OrigDocInfo, OrigParent1Info, OrigParent2Info;

        public PlayerUpdateForm(string url)
        {
            AddPlayerURL = url;
            InitializeComponent();

            IsNewPlayer = true;
        }

        // Let caller specify whether the user wants to add a new player or edit an existing player
        internal void SetUpdateFormType(bool isNewPlayer, Player player=null, Contact doctor=null,
            Contact parent1=null, Contact parent2=null)
        {
            IsNewPlayer = isNewPlayer;
            if (!IsNewPlayer)
            {
                OrigPlayerInfo = player;
                OrigDocInfo = doctor;
                OrigParent1Info = parent1;
                OrigParent2Info = parent2;
                PopulateInitialFieldValues();
            }
        }

        // Fill out text fields with current values so user can edit
        private void PopulateInitialFieldValues()
        {
            // player fields
            firstNameText.Text = OrigPlayerInfo.FirstName;
            lastNameText.Text = OrigPlayerInfo.LastName;
            jerseyNumberText.Text = OrigPlayerInfo.UniformNum.ToString();
            birthdayText.Text = OrigPlayerInfo.Birthday;
            heightText.Text = OrigPlayerInfo.Height.ToString();
            weightText.Text = OrigPlayerInfo.Weight.ToString();
            medicalHistoryText.Text = OrigPlayerInfo.MedicalHistory;
            docNotesText.Text = OrigPlayerInfo.DoctorNotes;
            phoneText.Text = OrigPlayerInfo.PhoneNumber;
            addressText.Text = OrigPlayerInfo.Address;

            // doctor fields
            if (OrigDocInfo != null)
            {
                docFirstNameTxt.Text = OrigDocInfo.FirstName;
                docLastNameTxt.Text = OrigDocInfo.LastName;
                docPhoneNumTxt.Text = OrigDocInfo.PhoneNumber;
                docAltPhoneNumTxt.Text = OrigDocInfo.AltPhoneNumber;
                docAddressTxt.Text = OrigDocInfo.Address;
            }

            // parent 1 fields
            if (OrigParent1Info != null)
            {
                parFirstNameTxt.Text = OrigParent1Info.FirstName;
                parLastNameTxt.Text = OrigParent1Info.LastName;
                parPhoneNumTxt.Text = OrigParent1Info.PhoneNumber;
                parAltPhoneNumTxt.Text = OrigParent1Info.AltPhoneNumber;
                parAddressTxt.Text = OrigParent1Info.Address;
                parRelComboBox.SelectedIndex = Convert.ToInt16(OrigParent1Info.Relation);
                parRelComboBox.Text = parRelComboBox.Items[parRelComboBox.SelectedIndex].ToString();
            }

            // parent 2 fields
            if (OrigParent2Info != null)
            {
                par2FirstNameTxt.Text = OrigParent2Info.FirstName;
                par2LastNameTxt.Text = OrigParent2Info.LastName;
                par2PhoneNumTxt.Text = OrigParent2Info.PhoneNumber;
                par2AltPhoneNumTxt.Text = OrigParent2Info.AltPhoneNumber;
                par2AddressTxt.Text = OrigParent2Info.Address;
                par2RelComboBox.SelectedIndex = Convert.ToInt16(OrigParent2Info.Relation);
                par2RelComboBox.Text = "";
                par2RelComboBox.Text = par2RelComboBox.Items[par2RelComboBox.SelectedIndex].ToString();
            }
        }

        // User clicked cancel button on Add New Player Form
        private void cancelButton_Click(object sender, EventArgs e)
        {
            ResetNewPlayerFormFields();
        }

        // User filled out the form and wants to create the new player
        private void SaveButton_Click(object sender, EventArgs e)
        {
            using (var client = new System.Net.WebClient())
            {
                var doesDocExist = !docFirstNameTxt.Text.Equals(String.Empty);
                var doesPar1Exist = !parFirstNameTxt.Text.Equals(String.Empty);
                var doesPar2Exist = !par2FirstNameTxt.Text.Equals(String.Empty);

                if (doesPar2Exist && !doesPar1Exist)
                {
                    MessageBox.Show("Cannot have a secondary parent without having a primary parent.");
                }
                else if (ArePlayerFieldsValid()
                    && (!doesDocExist || (doesDocExist && AreDoctorFieldsValid()))
                    && (!doesPar1Exist || (doesPar1Exist && AreParentFieldsValid())))
                {
                    var playerUrl = AddPlayerURL + "/api/v1/player/";
                    var contactUrl = AddPlayerURL + "/api/v1/contact/";
                    try
                    {
                        // send information to database
                        if (IsNewPlayer)
                        {
                            // create new player in database
                            InsertPlayer(playerUrl, client);

                            // get new player's sensor id
                            var players = StatusViewerForm.GetListOfPlayers();
                            var newPlayerId = players.Find(p 
                                => p.UniformNum.ToString().Equals(jerseyNumberText.Text)).SensorId;

                            // create contacts for this new player
                            if (doesDocExist)
                            {
                                InsertDoctor(contactUrl, client, newPlayerId);
                            }
                            if (doesPar1Exist)
                            {
                                InsertParent1(contactUrl, client, newPlayerId);
                            }
                            if (doesPar2Exist)
                            {
                                InsertParent2(contactUrl, client, newPlayerId);
                            }
                        }
                        else
                        {
                            UpdatePlayer(playerUrl, client);

                            // edit doc
                            if (OrigDocInfo != null)
                            {
                                UpdateDoctor(contactUrl, client);
                            }
                            // add doc
                            else if (doesDocExist)
                            {
                                InsertDoctor(contactUrl, client, OrigPlayerInfo.SensorId);
                            }

                            // edit parent 1
                            if (OrigParent1Info != null)
                            {
                                UpdateParent1(contactUrl, client);
                            }
                            // add parent 1
                            else if (doesPar1Exist)
                            {
                                InsertParent1(contactUrl, client, OrigPlayerInfo.SensorId);
                            }

                            // edit parent 2
                            if (OrigParent2Info != null)
                            {
                                UpdateParent2(contactUrl, client);
                            }
                            // add parent 2
                            else if (doesPar2Exist)
                            {
                                InsertParent2(contactUrl, client, OrigPlayerInfo.SensorId);
                            }
                        }

                        ResetNewPlayerFormFields();
                    }
                    catch (SystemException exception)
                    {
                        Console.WriteLine("Error: " + exception.Message);
                        MessageBox.Show("Error while trying to update player information.");
                    }
                }
            }
        }

        // updates the player information in the database
        private void UpdatePlayer(string url, System.Net.WebClient client)
        {
            var info = "firstname=" + firstNameText.Text
            + ";lastname=" + lastNameText.Text
            + ";weight=" + weightText.Text
            + ";height=" + heightText.Text
            + ";number=" + jerseyNumberText.Text
            + ";phone=" + phoneText.Text
            + ";birthday=" + birthdayText.Text
            + ";address=" + addressText.Text
            + ";comments=" + docNotesText.Text
            + ";history=" + medicalHistoryText.Text;
            client.UploadString(url + OrigPlayerInfo.SensorId, "PUT", info);
        }

        // updates the player's doctor information in the database
        private void UpdateDoctor(string url, System.Net.WebClient client)
        {
            var info = "firstname=" + docFirstNameTxt.Text
            + ";lastname=" + docLastNameTxt.Text
            + ";phone=" + docPhoneNumTxt.Text
            + ";altphone=" + docAltPhoneNumTxt.Text
            + ";address=" + docAddressTxt.Text;
            client.UploadString(url + OrigDocInfo.Id, "PUT", info);
        }

        // updates the player's parent 1 information in the database
        private void UpdateParent1(string url, System.Net.WebClient client)
        {
            var info = "firstname=" + parFirstNameTxt.Text
            + ";lastname=" + parLastNameTxt.Text
            + ";phone=" + parPhoneNumTxt.Text
            + ";altphone=" + parAltPhoneNumTxt.Text
            + ";address=" + parAddressTxt.Text
            + ";relation=" + parRelComboBox.SelectedIndex.ToString();
            client.UploadString(url + OrigParent1Info.Id, "PUT", info);
        }

        // updates the player's parent 2 information in the database
        private void UpdateParent2(string url, System.Net.WebClient client)
        {
            // update parent 2 if there is one
            var info2 = "firstname=" + par2FirstNameTxt.Text
            + ";lastname=" + par2LastNameTxt.Text
            + ";phone=" + par2PhoneNumTxt.Text
            + ";altphone=" + par2AltPhoneNumTxt.Text
            + ";address=" + par2AddressTxt.Text
            + ";relation=" + par2RelComboBox.SelectedIndex.ToString();
            client.UploadString(url + OrigParent2Info.Id, "PUT", info2);
        }

        // adds a new player to the database
        private void InsertPlayer(string url, System.Net.WebClient client)
        {
            var values = new NameValueCollection();
            values.Add("firstname", firstNameText.Text);
            values.Add("lastname", lastNameText.Text);
            values.Add("weight", weightText.Text);
            values.Add("height", heightText.Text);
            values.Add("number", jerseyNumberText.Text);
            values.Add("phone", phoneText.Text);
            values.Add("birthday", birthdayText.Text);
            values.Add("address", addressText.Text);
            values.Add("comments", docNotesText.Text);
            values.Add("history", medicalHistoryText.Text);
            client.UploadValues(url, "POST", values);
        }

        // adds a doctor to the database for the new player 
        private void InsertDoctor(string url, System.Net.WebClient client, int playerId)
        {
            var values = new NameValueCollection();
            values.Add("firstname", docFirstNameTxt.Text);
            values.Add("lastname", docLastNameTxt.Text);
            values.Add("phone", docPhoneNumTxt.Text);
            values.Add("altphone", docAltPhoneNumTxt.Text);
            values.Add("address", docAddressTxt.Text);
            values.Add("relation", "1");
            values.Add("player", playerId.ToString());
            client.UploadValues(url, "POST", values);
        }

        // adds a primary parent to the database for the new player 
        private void InsertParent1(string url, System.Net.WebClient client, int playerId)
        {
            var values = new NameValueCollection();
            values.Add("firstname", parFirstNameTxt.Text);
            values.Add("lastname", parLastNameTxt.Text);
            values.Add("phone", parPhoneNumTxt.Text);
            values.Add("altphone", parAltPhoneNumTxt.Text);
            values.Add("address", parAddressTxt.Text);
            values.Add("relation", parRelComboBox.SelectedIndex.ToString());
            values.Add("player", playerId.ToString());
            client.UploadValues(url, "POST", values);
        }

        // adds a secondary parent to the database for the player 
        private void InsertParent2(string url, System.Net.WebClient client, int playerId)
        {
            var values = new NameValueCollection();
            values.Add("firstname", par2FirstNameTxt.Text);
            values.Add("lastname", par2LastNameTxt.Text);
            values.Add("phone", par2PhoneNumTxt.Text);
            values.Add("altphone", par2AltPhoneNumTxt.Text);
            values.Add("address", par2AddressTxt.Text);
            values.Add("relation", par2RelComboBox.SelectedIndex.ToString());
            values.Add("player", playerId.ToString());
            client.UploadValues(url, "POST", values);
        }

        // Clear all the text boxes and hide the form
        private void ResetNewPlayerFormFields()
        {
            Hide();
            PlayerUpdateTabCntrl.SelectedIndex = 0;

            // reset player info fields
            firstNameText.Text = "";
            lastNameText.Text = "";
            jerseyNumberText.Text = "";
            birthdayText.Text = "";
            phoneText.Text = "";
            weightText.Text = "";
            heightText.Text = "";
            medicalHistoryText.Text = "";
            docNotesText.Text = "";
            addressText.Text = "";

            // reset doctor info fields
            docFirstNameTxt.Text = "";
            docLastNameTxt.Text = "";
            docPhoneNumTxt.Text = "";
            docAltPhoneNumTxt.Text = "";
            docAddressTxt.Text = "";

            // reset parent 1 info fields
            parFirstNameTxt.Text = "";
            parLastNameTxt.Text = "";
            parPhoneNumTxt.Text = "";
            parAltPhoneNumTxt.Text = "";
            parAddressTxt.Text = "";
            parRelComboBox.Text = "-Select One-";

            // reset parent 2 info fields
            par2FirstNameTxt.Text = "";
            par2LastNameTxt.Text = "";
            par2PhoneNumTxt.Text = "";
            par2AltPhoneNumTxt.Text = "";
            par2AddressTxt.Text = "";
            par2RelComboBox.Text = "-Select One-";
        }

        // Validate the form's player info tab contains all valid fields
        private bool ArePlayerFieldsValid()
        {
            String errorMsg = String.Empty;
            bool success = ValidateFirstName(firstNameText, ref errorMsg);
            success &= ValidateLastName(lastNameText, ref errorMsg);
            success &= ValidateJerseyNumber(jerseyNumberText, ref errorMsg);
            success &= ValidateBirthday(birthdayText, ref errorMsg);
            success &= ValidateHeight(heightText, ref errorMsg);
            success &= ValidateWeight(weightText, ref errorMsg);
            success &= ValidatePhoneNumber(phoneText, ref errorMsg);

            // show error if there is one
            if (!success && !errorMsg.Equals(String.Empty))
            {
                PlayerUpdateTabCntrl.SelectedIndex = 0;
                MessageBox.Show(errorMsg, "Invalid field", MessageBoxButtons.OK);
            }

            return success;
        }

        // Validate the form's doctor info tab contains all valid fields
        private bool AreDoctorFieldsValid()
        {
            String errorMsg = String.Empty;
            bool success = ValidateFirstName(docFirstNameTxt, ref errorMsg);
            success &= ValidateLastName(docLastNameTxt, ref errorMsg);
            success &= ValidatePhoneNumber(docPhoneNumTxt, ref errorMsg);
            success &= ValidatePhoneNumber(docAltPhoneNumTxt, ref errorMsg);

            // show error if there is one
            if (!success && !errorMsg.Equals(String.Empty))
            {
                PlayerUpdateTabCntrl.SelectedIndex = 2;
                MessageBox.Show(errorMsg, "Invalid field", MessageBoxButtons.OK);
            }

            return success;
        }

        // Validate the form's parent info tab contains all valid fields
        private bool AreParentFieldsValid()
        {
            String errorMsg = String.Empty;
            bool success = ValidateFirstName(parFirstNameTxt, ref errorMsg);
            success &= ValidateLastName(parLastNameTxt, ref errorMsg);
            success &= ValidatePhoneNumber(parPhoneNumTxt, ref errorMsg);
            success &= ValidatePhoneNumber(parAltPhoneNumTxt, ref errorMsg);

            // validate parent 2 info
            if (!par2FirstNameTxt.Text.Equals(String.Empty))
            {
                success &= ValidateFirstName(par2FirstNameTxt, ref errorMsg);
                success &= ValidateLastName(par2LastNameTxt, ref errorMsg);
                success &= ValidatePhoneNumber(par2PhoneNumTxt, ref errorMsg);
                success &= ValidatePhoneNumber(par2AltPhoneNumTxt, ref errorMsg);
            }

            // show error if there is one
            if (!success && !errorMsg.Equals(String.Empty))
            {
                PlayerUpdateTabCntrl.SelectedIndex = 1;
                MessageBox.Show(errorMsg, "Invalid field", MessageBoxButtons.OK);
            }

            return success;
        }

        // Validate the First Name field
        private bool ValidateFirstName(TextBox input, ref String error)
        {
            bool success = true;
            Match match = LettersOnlyRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: First Name cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field contains only letters
            else if (!match.Success)
            {
                error = "Error: First Name should only contain letters.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Last Name field
        private bool ValidateLastName(TextBox input, ref String error)
        {
            bool success = true;
            Match match = LettersOnlyRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: Last Name cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field contains only letters
            else if (!match.Success)
            {
                error = "Error: Last Name should only contain letters.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Jersey Number field
        private bool ValidateJerseyNumber(TextBox input, ref String error)
        {
            bool success = true;
            Match match = DigitsOnlyRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: Jersey Number cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field contains only numbers
            else if (!match.Success)
            {
                error = "Error: Jersey Number should only contain numbers.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Birthday field
        private bool ValidateBirthday(TextBox input, ref String error)
        {
            bool success = true;
            Match match = BirthdayRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: Birthday cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field is in correct format
            else if (!match.Success)
            {
                error = "Error: Birthday is in invalid format.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Height field
        private bool ValidateHeight(TextBox input, ref String error)
        {
            bool success = true;
            Match match = DecimalNumberRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: Height cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field contains only numbers and potentially a decimal
            else if (!match.Success)
            {
                error = "Error: Height should be in decimal number format.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Weight field
        private bool ValidateWeight(TextBox input, ref String error)
        {
            bool success = true;
            Match match = DecimalNumberRegex.Match(input.Text);

            // this is a required field...make it's filled in
            if (input.Text == "")
            {
                error = "Error: Weight cannot be empty.";
                input.Focus();
                success = false;
            }
            // make sure field contains only numbers and potentially a decimal
            else if (!match.Success)
            {
                error = "Error: Weight should be in decimal number format.";
                input.Focus();
                success = false;
            }

            return success;
        }

        // Validate the Phone Number field
        private bool ValidatePhoneNumber(TextBox input, ref String error)
        {
            bool success = true;
            Match match = PhoneNumberRegex.Match(input.Text);

            // make sure field contains phone number format 2011-11-21
            if (input.Text != String.Empty && !match.Success)
            {
                error = "Error: Phone Number is in invalid format.";
                input.Focus();
                success = false;
            }

            return success;
        }
    }
}
